/*
 * Copyright 2009-2010 Nanjing RedOrange ltd (http://www.red-orange.cn)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package redora.client.ui;

import java.util.HashMap;

import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.InputElement;
import com.google.gwt.dom.client.NodeList;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.HasChangeHandlers;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.ui.*;
import redora.client.EnumDisplay;

/**
 * Enum Widget in GWT.
 *
 * @author Nanjing RedOrange (http://www.red-orange.cn)
 */
public class EnumWidget extends FocusWidget implements HasName,
        HasChangeHandlers, HasValue<String> {

    private int maxRadioButtons;
    private int widgetWidth;

    String name;
    String id = "";
    String styleName = "";
    String title;

    boolean enabled = true;

    final HashMap<String, String> values = new HashMap<String, String>();

    ListBox listBox;
    CellPanel radioPanel;
    EnumDisplay defaultValue;

    boolean isInit() {
        return !(listBox == null && radioPanel == null);
    }

    public EnumWidget(String name, int maxRadioButtons, int widgetWidth) {
        setName(name);
        this.maxRadioButtons = maxRadioButtons;
        this.widgetWidth = widgetWidth;
    }

    public EnumWidget(String name, int maxRadioButtons, int widgetWidth, EnumDisplay defaultValue) {
        setName(name);
        this.maxRadioButtons = maxRadioButtons;
        this.widgetWidth = widgetWidth;
        this.defaultValue = defaultValue;
    }

    public String getValue() {
        if (radioPanel != null) {
            NodeList<Element> items = radioPanel.getElement().getElementsByTagName("input");
            for (int i = 0; i < items.getLength(); i++) {
                Element element = items.getItem(i);
                if (InputElement.as(element).isChecked())
                    return InputElement.as(element).getValue();
            }
            return null;
        } else {
            return listBox.getSelectedIndex() == -1 ? null : listBox.getValue(listBox.getSelectedIndex());
        }
    }

    public void setValue(String value) {
        if (radioPanel != null) {
            NodeList<Element> items = radioPanel.getElement().getElementsByTagName("input");
            for (int i = 0; i < items.getLength(); i++) {
                Element element = items.getItem(i);
                if (value != null && InputElement.as(element).getValue().equals(value))
                    InputElement.as(element).setChecked(true);
                else
                    InputElement.as(element).setChecked(false);
            }
        } else {
            if (value == null)
                listBox.setSelectedIndex(-1);
            else
                for (int i = 0; i < listBox.getItemCount(); i++) {
                    if (listBox.getValue(i).equals(value))
                        listBox.setSelectedIndex(i);
                }
        }
    }

    public void setDefault(EnumDisplay defaultValue) {
        this.defaultValue = defaultValue;
        setSelected(defaultValue.name());
    }

    public void setValue(String value, boolean fireEvents) {
        setValue(value);
        if (fireEvents)
            ValueChangeEvent.fire(this, value);
    }

    public void addItem(String value, String label) {
        this.values.put(label, value);
    }

    public void addValues(EnumDisplay[] values) {
        HashMap<String, String> newValues = new HashMap<String, String>();
        for (EnumDisplay value : values) {
             newValues.put(value.displayForm(), value.name());
        }
        addValues(newValues);
    }

    @Deprecated
    public void addValues(HashMap<String, String> newValues) {
        this.values.putAll(newValues);

        if (!isInit()) {
            if (values.size() > this.maxRadioButtons) {
                listBox = new ListBox();
                //TODO fix init bug
                listBox.setName(getName());
                if (styleName != null && styleName.length() > 0)
                    listBox.addStyleName(styleName);
                listBox.setTitle(title);
                listBox.getElement().setId(id);
                listBox.setEnabled(enabled);
            } else {
                if (values.size() > widgetWidth) {
                    radioPanel = new VerticalPanel();
                } else {
                    radioPanel = new HorizontalPanel();
                }
                //TODO fix init bug
                if (styleName != null && styleName.length() > 0)
                    radioPanel.addStyleName(styleName);
                radioPanel.setTitle(title);
                radioPanel.getElement().setId(id);
                radioPanel.setSpacing(0);
                setElement(radioPanel.getElement());
            }
        }

        if (listBox != null) {
            for (String key : values.keySet()) {
                listBox.addItem(key, values.get(key));
                if (defaultValue != null && key.equals(defaultValue.displayForm()))
                    listBox.setSelectedIndex(listBox.getItemCount()-1);
            }
            setElement(listBox.getElement());
        } else {
            for (String key : values.keySet()) {
                if (key != null && key.trim().length() > 0) {
                    String formValue = values.get(key);
                    final RadioButton button = new RadioButton(getName(),
                            key);
                    button.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
                        @Override
                        public void onValueChange(ValueChangeEvent<Boolean> booleanValueChangeEvent) {
                            setValue(button.getFormValue(), true);
                        }
                    });
                    button.setFormValue(formValue);
                    button.setEnabled(enabled);
                    if (defaultValue != null && key.equals(defaultValue.displayForm()))
                        button.setValue(true);
                    radioPanel.add(button);
                }
            }
        }
    }

    @Deprecated
    public void setSelected(String value) {
        if (radioPanel != null) {
            NodeList<Element> radios = radioPanel.getElement().getElementsByTagName("input");
            for (int i = 0; i < radios.getLength(); i++) {
                Element element = radios.getItem(i);
                if (InputElement.as(element).getValue().equals(value))
                    InputElement.as(element).setChecked(true);
                else
                    InputElement.as(element).setChecked(false);
            }
        } else {
            for (int i = 0; i < listBox.getItemCount(); i++) {
                if (listBox.getValue(i).equals(value))
                    listBox.setSelectedIndex(i);
            }
        }
    }

    public HandlerRegistration addChangeHandler(ChangeHandler handler) {
        return addDomHandler(handler, ChangeEvent.getType());
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setStyleName(String style) {
        if (isInit())
            super.setStyleName(style);
        else
            styleName = style;
    }

    public void addStyleName(String style) {
        if (isInit())
            super.addStyleName(style);
        else
            styleName = styleName + " " + style;
    }

    public String getStyleName() {
        return styleName;
    }

    public void setTitle(String title) {
        if (isInit())
            super.setTitle(title);
        else
            this.title = title;
    }

    public String getTitle() {
        return title;
    }

    public void setEnabled(boolean enabled) {
        if (isInit())
            super.setEnabled(enabled);
        else
            this.enabled = enabled;
    }

    public HandlerRegistration addValueChangeHandler(ValueChangeHandler<String> stringValueChangeHandler) {
        return addHandler(stringValueChangeHandler, ValueChangeEvent.getType());
    }
}
